Skip to content

Convert utils gestures/, traversal/ and core node utilities to Kotlin (with characterization tests)#38

Open
jonathandasilvasantos wants to merge 2 commits into
google:masterfrom
jonathandasilvasantos:kotlin-port-utils
Open

Convert utils gestures/, traversal/ and core node utilities to Kotlin (with characterization tests)#38
jonathandasilvasantos wants to merge 2 commits into
google:masterfrom
jonathandasilvasantos:kotlin-port-utils

Conversation

@jonathandasilvasantos

Copy link
Copy Markdown

Summary

This PR converts 41 Java files in the utils module to Kotlin, with zero intended behavior change:

  • the full gestures/ package — GestureMatcher base, GestureManifold, GestureMatcherFactory and all 18 matchers (MultiTap, Swipe, multi-finger, second-finger/split-tap, touch-explore accelerators);
  • the full traversal/ package — OrderedTraversalStrategy/Controller, DirectionalTraversalStrategy, WorkingTree, ReorderedChildrenIterator, TraversalStrategyUtils;
  • the core node utilities — AccessibilityNodeInfoUtils, Role, FocusFinder, WebInterfaceUtils, AccessibilityNodeInfoRef, ScrollableNodeInfo.

Methodology: characterization tests first

The repository ships no unit tests, so each file was converted under a test harness built for this purpose:

  1. 123 JUnit/Robolectric characterization tests were written against the original Java sources and run green first, pinning observable behavior: gesture state machines and their exact timeouts/slops (double-tap window measured UP→DOWN, swipe 1 cm/150 ms confirmation, multi-finger tap timeouts scaling with finger count), traversal pre-order and cycle protection, focus rules (shouldFocusNode, speaking-node semantics), scroll-direction fallbacks, and edge-case contracts (e.g. roundForProgressPercent never rounding to 0/100 inside the open interval; isScrollable deliberately ignoring the node flag).
  2. Each file was then converted and the same tests re-run unchanged against the Kotlin.

Compatibility

  • All public signatures preserved for Java callers (@JvmStatic, @JvmField for the FILTER_* fields, const val; -Xjvm-default=all so Kotlin interface defaults remain real Java default methods).
  • Package-private members map to internal; @AutoValue nested classes are hand-written value classes with identical APIs (accessors, create() factories, AutoValue-format equals/hashCode/toString).
  • Full APK builds for both phone and wear flavors; the complete unit-test suite passes.

The first commit contains build prerequisites only: a pinned Gradle 8.13 wrapper (AGP 8.11.1 requires ≥ 8.13), an NDK bump to 27.2 for the braille modules (r21 cannot run on Apple Silicon hosts), and the -Xjvm-default=all compiler flag.

Happy to split this into smaller PRs (per package), adjust conventions, or sign whatever CLA process applies.

…m-default

- Pin Gradle 8.13 via wrapper (AGP 8.11.1 requires >= 8.13; the repo ships
  no wrapper, so builds depend on whichever system Gradle is installed).
- Bump ndkVersion 21.4.7075529 -> 27.2.12479018 in the braille modules:
  NDK r21 has no darwin-arm64 toolchain and fails on Apple Silicon hosts
  with "Unknown host CPU architecture: arm64".
- Compile Kotlin with -Xjvm-default=all so Kotlin interface defaults are
  emitted as real Java default methods (required for Java implementers of
  interfaces that migrate to Kotlin).
Mechanical, behavior-preserving Java -> Kotlin conversion of 41 files:
the full gestures/ package (GestureMatcher base, GestureManifold, factory
and all 18 matchers), the full traversal/ package (ordered + directional
strategies, WorkingTree, utils), and the core node utilities
(AccessibilityNodeInfoUtils, Role, FocusFinder, WebInterfaceUtils,
AccessibilityNodeInfoRef, ScrollableNodeInfo).

Every file was converted under a characterization-test harness: 123 new
JUnit/Robolectric tests were written against the original Java sources
first, then re-run unchanged against the converted Kotlin, pinning the
observable behavior (state machines, timeouts, slops, traversal order,
focus rules). All public signatures are preserved for Java callers via
@JvmStatic/@JvmField/const; package-private members map to internal;
@autovalue classes are hand-written value classes with identical APIs.

No behavior change intended. Full APK (phone + wear) builds; the whole
unit-test suite passes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant